#include "ObjFile.h"

using std::ifstream;
using std::stringstream;
using std::string;
using std::vector;

using namespace ObjData;

void ObjFile::Load(char* Path) {
	ifstream File(Path);
	if(!File.is_open())
		return;

	string Line;
	m_Objects.push_back(Object());

	while(std::getline(File, Line))
		m_ParseLine(stringstream(Line));

	File.close();
}

void ObjFile::m_ParseLine(std::istream &LineStr) {
	string Prefix;
	LineStr >> Prefix;

	if(Prefix.find("#")!=string::npos)
		return;

	if(Prefix.find("vn")!=string::npos) { // Vertex Normal
		LineStr >> m_fWorkArea[0] >> m_fWorkArea[1] >> m_fWorkArea[2];
		m_Norm.push_back(Vector3(m_fWorkArea));
	}

	if(Prefix.find("vt")!=string::npos) { // Vertex Texture Coordinate
		LineStr >> m_fWorkArea[0] >> m_fWorkArea[1];
		m_Tex.push_back(Vector2(m_fWorkArea));
		m_Tex.back().y *= -1.0;
	}

	if(Prefix.find("v")!=string::npos) { // Vertex Position in object space
		LineStr >> m_fWorkArea[0] >> m_fWorkArea[1] >> m_fWorkArea[2];
		m_Pos.push_back(Vector3(m_fWorkArea));
	}

	if(Prefix.find("usemtl")!=string::npos) {
		LineStr >> m_Objects.back().Mtrl;
	}

	if(Prefix.find("g")!=string::npos) {
		m_Objects.push_back(Object());
		std::getline(LineStr, m_Objects.back().Name);
		m_Objects.back().Name = m_Objects.back().Name.substr(1, m_Objects.back().Name.size() - 1);
	}

	if(Prefix.find("mtllib")!=string::npos) {
		LineStr >> m_MtrlLib;
	}

	if(Prefix.find("f")!=string::npos) { // New face
		Face f;
		while(LineStr.peek() != EOF) {
			Point v; // Read one vertex at a time
			string Vert;
			LineStr >> Vert;
			stringstream sVert(Vert);

			// Old way, easy but buggy!
			//sscanf_s(str.c_str(), "%d / %d / %d", &v.Position, &v.Texture, &v.Normal);

			int a = 0;
			char c;

			while(sVert.peek() != EOF) {
				if(sVert.peek() == '/')
					sVert.read(&c, 1);
				else {
					sVert >> v.Data[a];
					a++;
				}
			}

			// Convert relative indices to absolute indices
			if(v.Position < 0)
				v.Position = m_Pos.size() - v.Position;
			if(v.Normal < 0)
				v.Normal = m_Norm.size() - v.Normal;
			if(v.Texture < 0)
				v.Texture = m_Tex.size() - v.Texture;

			f.Points.push_back(v);
		}
		m_Objects.back().Faces.push_back(f);
	}
}

void ObjFile::Build(ObjPrimitive &Prim) {
	Prim.SetParams(&m_Pos, &m_Tex, &m_Norm);
	Prim.BuildObject(&m_Objects[0]);
}